Skip to main content
Glama

generic-mcp-server

# Instructions for Creating an MCP Server This document provides comprehensive guidance for Language Models (LLMs) on how to create a Model Context Protocol (MCP) server. These instructions emphasize modularity, organization, and maintainability as core requirements. ## Core Requirements When creating an MCP server, you **MUST** adhere to these fundamental principles: 1. **Modularity**: Break down functionality into logical, self-contained modules with clear responsibilities. 2. **Smaller Files**: Keep individual files focused and concise (ideally under 300 lines) to reduce cognitive load and make them easier to ingest. 3. **Clear Organization**: Follow a consistent directory structure that separates concerns. 4. **Type Safety**: Use TypeScript with proper type definitions throughout the codebase. 5. **Comprehensive Documentation**: Document all components, interfaces, and extension points. ## Project Structure Organize your MCP server using this structure: ``` mcp-server/ ├── src/ │ ├── services/ # Service classes for API interactions │ │ ├── base-service.ts # Abstract base service with common functionality │ │ └── specific-service.ts # Concrete service implementations │ ├── tools/ # MCP tool definitions and handlers │ │ ├── tool-definitions.ts # Tool schemas (name, description, inputSchema) │ │ └── tool-handlers.ts # Tool implementation logic │ ├── types/ # TypeScript type definitions │ │ └── domain-types.ts # Domain-specific type definitions │ ├── config.ts # Configuration management │ └── index.ts # Main entry point ├── .env.example # Example environment variables ├── package.json # Project dependencies and scripts ├── tsconfig.json # TypeScript configuration └── README.md # Project documentation ``` ## Step-by-Step Implementation Guide ### 1. Set Up Project Structure Begin by creating the directory structure and configuration files: ```bash mkdir -p src/{services,tools,types} touch src/config.ts src/index.ts ``` ### 2. Define Configuration Management Create a centralized configuration system in `config.ts` that: - Loads environment variables - Provides type-safe access to configuration - Validates required settings - Handles command-line arguments Example: ```typescript // src/config.ts import dotenv from 'dotenv'; // Load environment variables dotenv.config(); export interface Config { apiKey: string; serviceUrl: string; // Add other configuration properties } // Create and validate configuration const config: Config = { apiKey: process.env.API_KEY || '', serviceUrl: process.env.SERVICE_URL || 'https://api.example.com', // Add other properties }; // Validate required fields const missingEnvVars = Object.entries(config) .filter(([key, value]) => { // Check required fields if (key === 'apiKey') return !value; return false; }) .map(([key]) => key); if (missingEnvVars.length > 0) { throw new Error(`Missing required environment variables: ${missingEnvVars.join(', ')}`); } export default config; ``` ### 3. Create Base Service Class Implement a base service class that handles common functionality: - HTTP requests with axios - Error handling - Rate limiting - Logging Example: ```typescript // src/services/base-service.ts import axios, { AxiosInstance } from 'axios'; export abstract class BaseService { protected client: AxiosInstance; constructor(baseURL: string, headers: Record<string, string>) { this.client = axios.create({ baseURL, headers }); // Add interceptors for error handling, rate limiting, etc. } // Common methods for API requests, error handling, etc. } ``` ### 4. Implement Domain-Specific Services Create service classes that extend the base service and implement domain-specific functionality: ```typescript // src/services/specific-service.ts import { BaseService } from './base-service.js'; import config from '../config.js'; import { ResourceType } from '../types/domain-types.js'; export class SpecificService extends BaseService { // Implement singleton pattern if needed private static instance: SpecificService; private constructor() { super(config.serviceUrl, { 'Authorization': `Bearer ${config.apiKey}`, 'Content-Type': 'application/json' }); } public static getInstance(): SpecificService { if (!SpecificService.instance) { SpecificService.instance = new SpecificService(); } return SpecificService.instance; } // Implement domain-specific methods async getResources(): Promise<ResourceType[]> { // Implementation } // Other methods... } ``` ### 5. Define Type Definitions Create clear type definitions for your domain objects: ```typescript // src/types/domain-types.ts export interface ResourceType { id: string; name: string; // Other properties } export interface CreateResourceData { name: string; // Other properties } // Other type definitions... ``` ### 6. Define MCP Tools Define the tools that your MCP server will expose: ```typescript // src/tools/tool-definitions.ts export const tools = [ { name: "get_resources", description: "Retrieve a list of resources", inputSchema: { type: "object", properties: { // Define input properties } } }, // Other tool definitions... ]; // Define handler function type export type ToolHandler = (args: any) => Promise<any>; // Map tool names to handlers export interface ToolHandlers { [toolName: string]: ToolHandler; } ``` ### 7. Implement Tool Handlers Create handlers for each tool that process arguments and call service methods: ```typescript // src/tools/tool-handlers.ts import { SpecificService } from '../services/specific-service.js'; import { ToolHandlers } from './tool-definitions.js'; export function createToolHandlers(service: SpecificService): ToolHandlers { return { get_resources: async (args: any) => { try { const resources = await service.getResources(); return { resources }; } catch (error) { console.error('Error in get_resources:', error); throw new Error(`Failed to get resources: ${error instanceof Error ? error.message : String(error)}`); } }, // Other handlers... }; } ``` ### 8. Create Main Entry Point Implement the main entry point that initializes services, registers tools, and starts the server: ```typescript // src/index.ts import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js"; import { SpecificService } from "./services/specific-service.js"; import { tools } from "./tools/tool-definitions.js"; import { createToolHandlers } from "./tools/tool-handlers.js"; async function main() { try { // Initialize services const service = SpecificService.getInstance(); // Create tool handlers const toolHandlers = createToolHandlers(service); // Create MCP server const server = new Server( { name: "your-mcp-server", version: "0.1.0", }, { capabilities: { tools: {}, } } ); // Register tool list handler server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools }; }); // Register tool call handler server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const toolName = request.params.name; const handler = toolHandlers[toolName]; if (!handler) { throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${toolName}` ); } const result = await handler(request.params.arguments); return { content: [ { type: "text", text: JSON.stringify(result, null, 2) } ] }; } catch (error) { // Error handling } }); // Connect to transport const transport = new StdioServerTransport(); await server.connect(transport); console.log("MCP Server running on stdio"); } catch (error) { console.error("Failed to start server:", error); process.exit(1); } } main().catch(console.error); ``` ## Best Practices for MCP Server Development ### Modularity Guidelines 1. **Single Responsibility Principle**: Each file should have a single, well-defined purpose. 2. **Interface Segregation**: Define clear interfaces between components. 3. **Dependency Injection**: Pass dependencies to components rather than creating them internally. 4. **Separation of Concerns**: Keep tool definitions separate from their implementations. ### File Size and Organization 1. **Keep Files Small**: Aim for files under 300 lines of code. 2. **Logical Grouping**: Group related functionality in the same directory. 3. **Consistent Naming**: Use a consistent naming convention for files and directories. 4. **Export Patterns**: Be explicit about what each module exports. ### Error Handling 1. **Comprehensive Error Handling**: Handle errors at all levels (service, tool, server). 2. **Informative Error Messages**: Provide clear error messages that help diagnose issues. 3. **Error Propagation**: Properly propagate errors up the call stack. 4. **Logging**: Log errors with appropriate context for debugging. ### Documentation 1. **JSDoc Comments**: Document all classes, methods, and interfaces. 2. **README**: Provide comprehensive documentation on how to use and extend the server. 3. **Code Examples**: Include examples of how to add new tools and services. 4. **Architecture Overview**: Document the overall architecture and design decisions. ## Extension Patterns When extending the MCP server with new functionality, follow these patterns: ### Adding a New Service 1. Create a new service class in `src/services/`. 2. Extend the base service class. 3. Implement domain-specific methods. 4. Add any necessary type definitions in `src/types/`. ### Adding New Tools 1. Define new tools in `src/tools/tool-definitions.ts`. 2. Implement handlers in `src/tools/tool-handlers.ts`. 3. Register the tools and handlers in `src/index.ts`. ## Testing Your MCP Server To test your MCP server: 1. Build the project: `npm run build` 2. Run the server: `npm start` 3. Test with an MCP client or using the MCP CLI tool. ## Common Pitfalls to Avoid 1. **Monolithic Files**: Avoid putting too much functionality in a single file. 2. **Tight Coupling**: Avoid tight coupling between components. 3. **Inconsistent Error Handling**: Ensure consistent error handling throughout the codebase. 4. **Missing Documentation**: Document all components and extension points. 5. **Hardcoded Configuration**: Use the configuration system instead of hardcoding values. By following these guidelines, you will create an MCP server that is modular, maintainable, and easy to extend.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/v4lheru/generic-mcp-template'

If you have feedback or need assistance with the MCP directory API, please join our Discord server